package org.springframework.data.elasticsearch.core;

import com.lost.octopus.es.helper.service.DocumentEsService;
import com.lost.octopus.es.helper.service.EsService;
import com.lost.octopus.es.processor.config.es.alias.EsAliasRemoveInfo;
import com.sunsharing.share.common.base.DateUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
import org.elasticsearch.client.RequestOptions;
import org.springframework.data.elasticsearch.core.index.AliasAction;
import org.springframework.data.elasticsearch.core.index.AliasActionParameters;
import org.springframework.data.elasticsearch.core.index.AliasActions;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.util.Assert;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 继承{@link DefaultIndexOperations}
 * 根据
 * @author zhangbh
 * @date 2022/10/31 0031 14:25
 */
@Log4j2
public class AliasIndexOperations extends DefaultIndexOperations {

    private final ElasticsearchRestTemplate restTemplate;
    private final DocumentEsService esService;

    public AliasIndexOperations(ElasticsearchRestTemplate restTemplate, Class<?> boundClass, DocumentEsService esService) {
        super(restTemplate, boundClass);
        this.restTemplate = restTemplate;
        this.esService = esService;
    }

    public AliasIndexOperations(ElasticsearchRestTemplate restTemplate, IndexCoordinates boundIndex, DocumentEsService esService) {
        super(restTemplate, boundIndex);
        this.restTemplate = restTemplate;
        this.esService = esService;
    }

    public EsService getEsService() {
        return esService;
    }

    @Override
    public boolean delete() {
        return esService.deleteIndex(getIndexCoordinates().getIndexName());
    }

    public boolean delete(String indexName) {
        if (StringUtils.isBlank(indexName)) {
            indexName = getIndexCoordinates().getIndexName();
        }
        return esService.deleteIndex(indexName);
    }

    @Override
    protected Settings doGetSettings(IndexCoordinates index, boolean includeDefaults) {

        Assert.notNull(index, "index must not be null");

        GetSettingsRequest getSettingsRequest = requestFactory.getSettingsRequest(index, includeDefaults);
        GetSettingsResponse response = restTemplate.execute(client -> client.indices()
                .getSettings(getSettingsRequest, RequestOptions.DEFAULT));

        // 简单获取真实indexName
        String realIndexName = esService.getRealIndexName(getIndexCoordinates().getIndexName());

        return ResponseConverter.fromSettingsResponse(response, realIndexName);
    }

    public boolean createWithMapping(IndexCoordinates coordinates) {
        Settings settings;
        String indexName = getIndexCoordinates().getIndexName();
        // 判断是否存在
        boolean indexExist = esService.indexExist(indexName);
        if (boundClass != null) {
            log.info("已经有绑定类，直接使用类={} 做初始化配置", boundClass.getName());
            settings = createSettings(boundClass);
        } else {
            log.info("没有绑定类信息，需要从原有索引={} 获取配置信息,索引是否存在={}", indexName, indexExist);
            if (!indexExist) {
                return false;
            }
            settings = getSettings();
            // 删除原有索引相关的配置,类似模板配置。否则会报错,之后再研究
            String[] oldConfig = new String[]{"index.uuid", "index.provided_name", "index.creation_date", "index.version.created"};
            for (String config : oldConfig) {
                settings.remove(config);
            }
        }
        boolean result = doCreate(coordinates, settings, createMapping());
        if (!indexExist) {
            log.info("索引不存在，直接加别名 ={}", indexName);
            addByOriginalAlias(coordinates);
        }
        return result;
    }

    public IndexCoordinates getTimestampAlias(String name) {
        if (StringUtils.isNotBlank(name)) {
            log.info("继续使用临时索引名称={}", name);
            return IndexCoordinates.of(name);
        }
        String indexName = getIndexCoordinates().getIndexName();
        // 根据时间戳，创建索引
        String newIndex = indexName + "_" + DateUtil.toString14(LocalDateTime.now());
        log.info("获得临时索引名称索引={}", newIndex);
        return IndexCoordinates.of(newIndex);
    }

    /**
     * 将别名索引，增加别名（别名=原有类上的索引名）
     * @param coordinates 别名的索引，
     */
    public void addByOriginalAlias(IndexCoordinates coordinates) {
        String original = getIndexCoordinates().getIndexName();
        String alias = coordinates.getIndexName();
        log.info("索引={} 增加别名={}", alias, original);
        AliasActions aliasActions = new AliasActions(new AliasAction.Add(AliasActionParameters.builder()
                .withIndices(alias).withAliases(original).build()));
        alias(aliasActions);
    }

    /**
     * 刷新指定索引
     * @param indexCoordinates 索引对象
     */
    public void refresh(IndexCoordinates indexCoordinates) {
        doRefresh(indexCoordinates);
    }

    /**
     * 修改别名为删除
     * @return 是否是初始化索引，如果是初始化索引
     */
    public EsAliasRemoveInfo removeAlias() {
        String original = getIndexCoordinates().getIndexName();
        String realIndexName = esService.getRealIndexName(original);
        if (StringUtils.isBlank(realIndexName) || !exists()) {
            log.info("没有找到索引信息={}", original);
            return new EsAliasRemoveInfo(false, null);
        }
        if (Objects.equals(realIndexName, original)) {
            log.info("索引={} 已经是初始化索引，不需要删除别名", original);
            return new EsAliasRemoveInfo(true, realIndexName);
        }
        log.info("索引={} 删除索引别名={}", realIndexName, original);
        AliasActions aliasActions = new AliasActions(new AliasAction.Remove(AliasActionParameters.builder()
                .withIndices(realIndexName).withAliases(original).build()));
        alias(aliasActions);
        return new EsAliasRemoveInfo(false, realIndexName);
    }
}
